import os
import uuid
import logging
from pathlib import Path
from django.db import models
from .test_framework.ui_framework import UITestFramework
from .test_framework.api_framework import APITestFramework
from django.core.exceptions import ValidationError

logger = logging.getLogger(__name__)

def validate_file_extension(value):
    ext = os.path.splitext(value.name)[1]
    valid_extensions = ['.yaml', '.xlsx']
    if not ext.lower() in valid_extensions:
        raise ValidationError('不支持的文件类型。')

def get_case_path(instance, filename):
    """
    获取用例文件保存路径，保存到tests/<id>/<filename>
    """
    return os.path.join('tests', str(instance.id), filename)

class TestTask(models.Model):
    """
    测试任务
    将用例文件上传到指定的目录，并在该目录执行用例
    """
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    name = models.CharField('任务名称', max_length=100)
    case_file = models.FileField('用例文件', upload_to=get_case_path, validators=[validate_file_extension])
    status = models.IntegerField('任务状态', default=-1, choices=[
        (-2, '执行出错'),
        (-1, '初始化'),
        (0, '去执行~'),
        (1, '执行用例'),
        (2, '生成报告'),
        (3, '执行完毕'),
    ])
    is_processing = models.BooleanField('正在执行', default=False, editable=False)
    is_pass = models.BooleanField('是否通过', default=False, editable=False)
    has_report = models.BooleanField('是否生成报告', default=False, editable=False)
    created_at = models.DateTimeField('创建时间', auto_now_add=True)
    updated_at = models.DateTimeField('更新时间', auto_now=True)
    test_type = models.CharField('测试类型', max_length=10, choices=[('UI', 'UI测试'), ('API', 'API测试')])

    class Meta:
        verbose_name = '测试任务'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name

    def clean(self):
        if self.test_type == 'UI' and not self.case_file.name.endswith('.xlsx'):
            raise ValidationError('UI测试必须上传Excel文件。')
        elif self.test_type == 'API' and not self.case_file.name.endswith('.yaml'):
            raise ValidationError('API测试必须上传YAML文件。')

    def save(self, *args, **kwargs):
        self.clean()
        super().save(*args, **kwargs)
        if self.status == 0 and not self.is_processing:
            self.execute_test()

    def execute_test(self):
        logger.info(f"开始执行测试任务: {self.name}")
        try:
            logger.debug(f"当前 PATH: {os.environ.get('PATH')}")
            self.status = 1
            self.is_processing = True
            self.save(update_fields=['status', 'is_processing'])
            logger.debug(f"更新任务状态: status={self.status}, is_processing={self.is_processing}")

            case_file = Path(self.case_file.path)
            allure_results_dir = case_file.parent / "allure_results"
            report_dir = case_file.parent / "report"

            logger.debug(f"测试文件路径: {case_file}")
            logger.debug(f"Allure结果目录: {allure_results_dir}")
            logger.debug(f"报告目录: {report_dir}")

            if self.test_type == 'UI':
                logger.info("执行UI测试")
                framework = UITestFramework(case_file, allure_results_dir)
            else:
                logger.info("执行API测试")
                framework = APITestFramework(case_file, allure_results_dir)

            res = framework.run_tests()
            logger.info(f"测试执行结果: {res}")

            self.is_pass = res == 0
            self.status = 2
            self.save(update_fields=['is_pass', 'status'])
            logger.debug(f"更新任务状态: is_pass={self.is_pass}, status={self.status}")

            # 检查 Allure 结果目录
            if not allure_results_dir.exists() or not list(allure_results_dir.glob('*-result.json')):
                logger.error(f"Allure 结果目录不存在或为空: {allure_results_dir}")
                self.has_report = False
            else:
                report_res = framework.generate_report(report_dir)
                self.has_report = report_res == 0
                logger.info(f"报告生成结果: {report_res}")

            if self.has_report:
                logger.info(f"报告已生成，请检查目录: {report_dir}")
                report_files = list(report_dir.glob('*'))
                logger.info(f"报告目录中包含 {len(report_files)} 个文件")
            else:
                logger.error("报告生成失败")

            self.status = 3
            self.is_processing = False
            self.save()
            logger.debug(f"更新任务状态: status={self.status}, is_processing={self.is_processing}")
            logger.info(f"测试任务执行完成: {self.name}")
        except Exception as e:
            logger.exception(f"测试执行过程中出现错误: {e}")
            self.status = -2
            self.is_processing = False
            self.save()
            logger.debug(f"更新任务状态: status={self.status}, is_processing={self.is_processing}")